#include "flowmeasure.h"
#include "ivdsmeasure.h"
#include "bllcontroller.h"
#include "globaldef.h"
#include "userlogger.h"
#include "logger.h"
#include <QThread>
#include <QDebug>
#include <QMutex>
#include <QWaitCondition>
#include <QElapsedTimer>
#include <QDateTime>

class FlowMeasurePrivate : public QThread
{
    Q_OBJECT
public:
    void start(FlowTest *data);
    void stop();

signals:
    void progress(const QString &info, bool stopped = false);
    void measureFinished(const IMeasureData &result);

private slots:
    void onCommRespond(const HostReply &info);

protected:
    void run() Q_DECL_OVERRIDE;

private:
    void startTest();

private:
    FlowTest *m_flowTest;
    QWaitCondition m_condition;
    QMutex m_mutex;
    QElapsedTimer m_timer;
    qint64 m_times;
};

FlowMeasure::FlowMeasure(QObject *parent) : IMeasure(parent), d(new FlowMeasurePrivate)
{
    connect(d, &FlowMeasurePrivate::progress, this, &IMeasure::progress);
}

FlowMeasure::~FlowMeasure()
{
    d->stop();
    d->disconnect();
    d->deleteLater();
}

void FlowMeasure::measure(IMeasureData *data)
{
    emit d->start(static_cast<FlowTest *>(data));
}

void FlowMeasurePrivate::start(FlowTest *data)
{
    if (isRunning())
    {
        sysError("Error: FlowMeasure running, cannot start agin.");
        return;
    }

    m_flowTest = data;
    QThread::start();
}

void FlowMeasurePrivate::stop()
{// 主动停止测试
    requestInterruption();
    m_condition.wakeAll();
    quit();
    wait();
}

void FlowMeasurePrivate::startTest()
{
    sysDebug("startTest(): volume = %fml, flow = %fml/min", m_flowTest->volume, m_flowTest->flow.setValue);
    connect(BllController::getInstance(), &BllController::pwdflwCheckResultSignal, this, &FlowMeasurePrivate::onCommRespond);

    ComCmd cmd;
    cmd.type = CMD_TYPE::FLWCHK;
    cmd.value1 = qRound(m_flowTest->volume * 100);
    cmd.value2 = qRound(m_flowTest->flow.setValue * 100 * gSpeedRatio);

    m_times = 0;
    QMutexLocker locker(&m_mutex);
    BllController::getInstance()->sendPortCmd(cmd);
    m_condition.wait(&m_mutex);

    m_timer.invalidate();
    disconnect(BllController::getInstance(), &BllController::pwdflwCheckResultSignal, this, &FlowMeasurePrivate::onCommRespond);
}

static const QMap<int, QString> mapper = {
    {0, "VoltageMeasure Started."},
    {1, "Liquid Detected."},
    {2, "Liquid Maybe Empty."},
    {3, "FlowMeasure Stopped."},
    {4, "Liquid Detect Timeout."},
};

void FlowMeasurePrivate::onCommRespond(const HostReply &info)
{
    int ctrlCode = info.parameter.toInt();
    sysDebug("FlowMeasurePrivate::onCommRespond(): ret=%d", ctrlCode);
    QString message(mapper.contains(ctrlCode) ? mapper[ctrlCode] : "Unknown respond");
    sysDebug("flowTest progress: %s", message.toStdString().data());

    if (!m_timer.isValid() && ctrlCode == 1)
    {// 检测到液体，开始计时
        sysDebug("startTime: %s", QTime::currentTime().toString("hh:mm:ss").toStdString().data());
        emit progress(tr("Liquid Detected."));
        m_timer.start();
        return;
    }

    if (m_timer.isValid() && ctrlCode == 2)
    {// 检测到液体流完，记录时间，但有可能是检测到了气泡
        sysDebug("emptyTime: %s", QTime::currentTime().toString("hh:mm:ss").toStdString().data());
        m_times = m_timer.elapsed();
        return;
    }

    if (ctrlCode == 3)
    {// 检测动作结束
        sysDebug("stopTime: %s", QTime::currentTime().toString("hh:mm:ss").toStdString().data());
        sysDebug("record Liquid flow times: %f", m_times / 1000.0);

        m_flowTest->flow.realValue = (m_times != 0) ? (m_flowTest->volume / m_times * 60000) : 0;
        emit progress(tr("FlowMeasure Finished."), true);
        m_condition.wakeAll();
        return;
    }

    if (ctrlCode == 4)
    {// 超时未检测到液体
        emit progress(tr("Liquid Detect Timeout."), true);
        UserLogger::error(info.message);
        m_condition.wakeAll();
    }
}

void FlowMeasurePrivate::run()
{
    sysDebug("Start FlowMeasure.");

    startTest();

    sysDebug("FlowMeasure Finished.");
}

#include "flowmeasure.moc"
